"""
作者: Sugobet
QQ: 321355478
Github:
脚本开源免费，使用前请先查阅readme.md文档
有任何问题请QQ联系，有必要时将会收取一定费用
二次开发
狼元星
QQ:3186444719
Github:
https://github.com/yuanxinglang
bilibili:
https://space.bilibili.com/516549721
"""

import os
import threading
import time
from ctypes import *
import cv2
import uiautomation as auto
import win32clipboard
import win32con
from PIL import Image, ImageFile, UnidentifiedImageError
from uiautomation.uiautomation import Bitmap
import pygame
import requests
import json
from datetime import datetime

ImageFile.LOAD_TRUNCATED_IMAGES = True

# 初始化pygame mixer模块
pygame.mixer.init()

con_val = 0.5  # 阈值：程序执行一遍的间隔时间，单位：秒
# 路径请勿出现中文
path = 'E:/GitHub/EVE_A_Eye_NEW'  # 脚本目录绝对路径 请将复制过来的路径的反斜杠修改成斜杠！
devices = {  # 模拟器地址，要开几个预警机就填对应预警机的模拟器的地址， 照抄
    'S1': [  # 星系名        请勿出现中文或中文字符以及特殊字符
        '127.0.0.1:5559',  # cmd输入adb devices查看模拟器地址
        False  # 没卵用，但不能少也不能改
    ],
}
game_send_position = {  # 从聊天框中第二个频道开始数，即系统频道之后为第二频道
    '第二频道': '38 117',  # 本地频道
    '第三频道': '38 170',  # 军团频道
    '第四频道': '38 223',  # 其他频道
    '第五频道': '38 278',  # 其他频道
    '第六频道': '38 332',  # 其他频道
    '第七频道': '38 382'   # 其他频道
}
sendTo = game_send_position['第三频道']  # 默认发送军团频道

# PushPlus配置
pushplus_enabled = True        # 是否启用PushPlus推送
pushplus_token = "秘钥"         # PushPlus的消息token
pushplus_topic = "群组号"  # 推送群组
pushplus_CD = 5          # 推送冷却时间(分钟)

mutex = threading.Lock()
last_push_time = {}  # 记录每个星系的上次推送时间

def get_current_time():
    """获取当前时间(精确到毫秒)"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]

def can_send_push(tag):
    """检查是否可以发送推送(根据冷却时间)"""
    current_time = time.time()
    if tag not in last_push_time:
        last_push_time[tag] = 0

    # 检查是否超过冷却时间
    return (current_time - last_push_time[tag]) >= (pushplus_CD * 60)

def update_last_push_time(tag):
    """更新最后推送时间"""
    last_push_time[tag] = time.time()

def play_alarm():
    # 加载并播放警报音频
    pygame.mixer.music.load(os.path.join(path, 'warning.mp3'))
    pygame.mixer.music.play()

def set_clipboard_file(paths):
    try:
        im = Image.open(paths)
        im.save('1.bmp')
        a_string = windll.user32.LoadImageW(0, r"1.bmp", win32con.IMAGE_BITMAP, 0, 0, win32con.LR_LOADFROMFILE)
    except UnidentifiedImageError:
        set_clipboard_file(paths)
        return

    if a_string != 0:
        win32clipboard.OpenClipboard()
        win32clipboard.EmptyClipboard()
        win32clipboard.SetClipboardData(win32con.CF_BITMAP, a_string)
        win32clipboard.CloseClipboard()
        return
    print('图片载入失败')

def send_game_massage(tag):
    str1 = f'adb -s {devices[tag][0]} '
    os.system(str1 + 'shell input tap 211 478')  # 进入聊天频道
    time.sleep(1)
    os.system(str1 + f'shell input tap {sendTo}')  # 进入目标频道
    time.sleep(0.5)
    os.system(str1 + 'shell input tap 266 520')  # 进入更多
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 870 515')  # 进入汇报
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 75 290')  # 进入情报
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 235 435')  # 写入侦查(汇报人数)
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 235 355')  # 写入警告(汇报舰船)
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 340 190')  # 点发送(退出更多)
    time.sleep(0.2)
    os.system(str1 + 'shell input tap 340 510')  # 发送
    time.sleep(1)
    os.system(str1 + 'shell input tap 774 502')  # 退出聊天区
    time.sleep(0.5)

def send_pushplus_notification(tag, title, content):
    """发送PushPlus通知"""
    if not pushplus_enabled or not pushplus_token:
        return

    # 检查冷却时间
    if not can_send_push(tag):
        remaining_time = round((pushplus_CD * 60) - (time.time() - last_push_time[tag]))
        print(f"{tag}推送冷却中，剩余{remaining_time}秒")
        return

    url = "https://www.pushplus.plus/send"

    # 添加当前时间到内容
    full_content = f"<p>时间: {get_current_time()}</p>{content}"

    payload = json.dumps({
        "token": pushplus_token,
        "title": title,
        "content": full_content,
        "topic": pushplus_topic,
        "template": "html"
    })

    headers = {
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(url, headers=headers, data=payload)
        response.raise_for_status()  # 检查请求是否成功
        print(f"PushPlus推送成功: {response.text}")
        update_last_push_time(tag)  # 更新最后推送时间
    except requests.exceptions.RequestException as e:
        print(f"PushPlus推送失败: {e}")

def start():
    # 启动时重置  ‘’图片
    with open(f'{path}/tem/list.png', 'rb') as sc1:
        con = sc1.read()
        for k in devices:
            f = open(f'{path}/new_{k}_list.png', 'wb')
            f.write(con)
            f.close()

    with open(f'{path}/tem/playerList.png', 'rb') as sc:
        con = sc.read()
        for k in devices:
            f = open(f'{path}/old_{k}_playerList.png', 'wb')
            f.write(con)
            f.close()
            f = open(f'{path}/new_{k}_playerList.png', 'wb')
            f.write(con)
            f.close()

    # 监听线程
    for k in devices:
        t = threading.Thread(target=listening, args=(k,))
        t.start()

    print('Started')
    context = f"预警系统已上线，监测星系列表：\n {list(devices.keys())}"
    # 发送启动通知
    send_pushplus_notification("系统", "预警系统启动", context)

def screenc(filename, num):
    os.system(f'adb -s {devices[filename][0]} exec-out screencap -p > {filename}_{num}.png')

def crop(x1, y1, x2, y2, sc_file_name, sv_file_name):
    try:
        img = Image.open(sc_file_name)
        re = img.crop((x1, y1, x2, y2))
        re.save(sv_file_name)
        img.close()
        re.close()
    except IOError:
        print("无法打开或读取文件")
    except ValueError:
        print("裁剪区域无效")
    except Exception as e:
        print("其他错误"+str(e))
        return

def load_image(img1, img2):
    i1 = cv2.imread(img1, 0)
    i2 = cv2.imread(img2, 0)
    return i1, i2

def if_img_i(src, mp):
    try:
        res = cv2.matchTemplate(src, mp, cv2.TM_CCOEFF_NORMED)
    except cv2.error as e:  # 捕获 OpenCV 相关的错误
        print("OpenCV 错误: "+str(e))
        return False, 0.999
    except ValueError as e:  # 捕获值错误，例如传入的参数类型不正确
        print("值错误: "+str(e))
        return False, 0.999
    except Exception as e:  # 捕获其他未预料到的异常
        print("其他错误: "+str(e))
        return False, 0.999

    _, mac_v, _, _ = cv2.minMaxLoc(res)
    if mac_v < 0.99:
        return True, mac_v
    return False, mac_v

def listening(tag):
    # *截图->裁剪->识别->动作（游戏频道发送，PushPlus推送）

    def task2(tag):
        num = 0
        while True:
            screenc(tag, 1)
            # 检测舰船列表
            time.sleep(0.5)
            crop(918, 44, 956, 153, f'{path}/{tag}_1.png', f'new_{tag}_list.png')
            i3, i4 = load_image(f"{path}/new_{tag}_list.png", f"{path}/tem/list.png")
            list_status, list_mac_v = if_img_i(i3, i4)

            if list_mac_v != 0.0 and list_mac_v < 0.10:
                if num < 1:
                    num += 1
                    print('二次检测')
                    time.sleep(2)
                    continue
                # 防误报  二次检测

                num = 0
                print(tag + '检测到舰船列表有人', list_mac_v)

                # 发送PushPlus通知
                content = f"<p>{tag}星系检测到舰船列表变化</p><p>相似度: {list_mac_v:.3f}</p>"
                send_pushplus_notification(tag, f"{tag}星系警告", content)

                i1, i2 = load_image(f"{path}/new_{tag}_playerList.png", f"{path}/old_{tag}_playerList.png")
                cv2.imwrite(f'{path}/old_{tag}_playerList.png', i1, [cv2.IMWRITE_PNG_COMPRESSION, 0])
                time.sleep(30)  # 播报一次后延迟播报,避免信息轰炸
                continue

    t = threading.Thread(target=task2, args=(tag,))
    t.start()

    while True:
        screenc(tag, 2)
        time.sleep(con_val)
        # 第一次识别后, 判断是否检测舰船列表, 动作结束后将new playerList覆盖掉old
        time.sleep(0.35)
        crop(263, 284, 451, 328, f'{path}/{tag}_2.png', f'new_{tag}_playerList.png')
        i1, i2 = load_image(f"{path}/new_{tag}_playerList.png", f"{path}/old_{tag}_playerList.png")
        list_status, list_mac_v = if_img_i(i1, i2)

        # 疑似故障等待
        if list_mac_v <= 0.01:
            print(tag, '检测失败,疑似元素位置错误')
            time.sleep(3)
            continue

        # 检测到本地有红白, 发送游戏频道和PushPlus通知
        if list_status:
            print(tag + '警告')
            play_alarm()  # 播放警报音频
            send_game_massage(tag)

            # 发送PushPlus通知
            content = f"<p>{tag}星系检测到敌对目标!</p><p>相似度: {list_mac_v:.3f}</p>"
            send_pushplus_notification(tag, f"{tag}星系紧急警告", content)

            cv2.imwrite(f'{path}/old_{tag}_playerList.png', i1, [cv2.IMWRITE_PNG_COMPRESSION, 0])
            time.sleep(5)

start()